package test;

/**
 * @author Sunkey
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
import java.util.Vector;

public class MsgBuffer implements IMsgBuffer, Cloneable {
	public int cap = IMsgBuffer.DEF_CAP;

	private int num = 0;

	private Vector<Object> buffer = new Vector<Object>();
	
	private Object putObj = new Object();
	
	private Object getObj = new Object();
	
	private Object numObj = new Object();
	

	public MsgBuffer() {
	}
	
	public MsgBuffer(int theCap) {
		this.cap = theCap;
	}
	
	protected void append() {
		synchronized(this.putObj){
			while (this.num == this.cap) {
				synchronized(this.getObj){
					this.getObj.notify();
				}
				try {
					this.putObj.wait();
				} catch (InterruptedException e) {
					System.out.println(
							"In DataBuffer, append has been interrupted");
					return;
				}
			}
			
			
			synchronized(this.numObj){
				++this.num;
			}
			
		}
//		notify();
		synchronized(this.getObj){
			this.getObj.notify();
		}
	}
	
	protected void detach() {
		synchronized(this.getObj){
			while (this.num == 0) {
				synchronized(this.putObj){
					this.putObj.notify();
				}
				try {
					this.getObj.wait();
				} catch (InterruptedException e) {
					System.out.println(
							"In DataBuffer, detach has been interrupted");
					return;
				}
			}
			
			synchronized(this.numObj){
				--this.num;
			}
			
			
		}
//		notify();
		synchronized(this.putObj){
			this.putObj.notify();
		}
	}
	
	public Object get() {
		detach();
		Object o = null;
		if (buffer.size() > 0)
			o = buffer.remove(0);// synchronized operation
		return o;
	}
	
	public void put(Object o) {
		buffer.add(o);// synchronized operation
		append();
	}
	
	public Object clone() {
		try {
			MsgBuffer buf = (MsgBuffer) super.clone();
			buf.buffer = new Vector<Object>();
			buf.getObj = new Object();
			buf.putObj = new Object();
			buf.numObj = new Object();
			return buf;
		} catch (CloneNotSupportedException e) {
			/* Never reach here. */
			return new MsgBuffer();
		}
	}

	public int getNum() {
		return num;
	}
	
	protected boolean detach(long time) {
		synchronized(this.getObj){
			if (this.num == 0) {
				synchronized(this.putObj){
					this.putObj.notify();
				}
				try {
					this.getObj.wait(time);
					if (this.num == 0)
						return false;
				} catch (InterruptedException e) {
					System.out.println(
							"In DataBuffer, detach has been interrupted");
					return false;
				}
			}
			synchronized(this.numObj){
				--this.num;
			}
		}
//		notify();
		synchronized(this.putObj){
			this.putObj.notify();
		}
		return true;
	}
	
	public Object get(long time) {
		if(detach(time)){
			Object o = null;
			if (buffer.size() > 0)
				o = buffer.remove(0);//synchronized operation
			return o;
		}else
			return null;
	}
	
	public synchronized void clear() {
		this.num = 0;
		this.buffer.clear();
	}
	
	protected void append1() {
		synchronized(this.putObj){
			while ((this.num + 1) >= this.cap){
				synchronized(this.getObj){
					this.getObj.notify();
				}
				try {
					this.putObj.wait();
				} catch (InterruptedException e) {
					System.out.println(
							"In DataBuffer, append has been interrupted");
					return;
				}
			}
		}
//		notify();
		synchronized(this.getObj){
			this.getObj.notify();
		}
	}
	
	public synchronized void put1(Object o) {
		if(this.cap<=1){
			put(o);
			return;
		}
		boolean ok = false;
		while (!ok) {
			if ((this.num + 1) < this.cap) {
				buffer.add(o);// synchronized operation
				append();
				ok = true;
			}else{
				append1();
			}
		}
	}

} // end of class
